package android_board;

//import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.GridLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android_codebehind.AndroidGUICar;
import android_codebehind.GUIFieldFactory;
import android_codebehind.GUIPlayer;
import android_fields.AndroidField;
import common.Car;
import common.GUIColor;
import dk.dtu.compute.course02312.matadordel2.MainActivity;
import dk.dtu.compute.course02312.matadordel2.R;

/**
 * The board
 * 
 * @author Ronnie
 */
public final class GUIBoard {
	@SuppressWarnings("unused")
	private static final long serialVersionUID = 1L;
	private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
	public static final int FONTSIZE = 10;
	protected static final GUIColor BASECOLOR = new GUIColor(MainActivity.context
			.getResources().getColor(R.color.basecolor));
	public static final int MAX_PLAYER_COUNT = 6;

	private static volatile GUIBoard instance;

	private GridLayout base;
	public static GUIPlayer[] playerList = new GUIPlayer[MAX_PLAYER_COUNT];
	private RelativeLayout[][] carPanes = new RelativeLayout[11][11];
	private static RelativeLayout[][] bgLayouts = new RelativeLayout[11][11];
	private ArrayList<AndroidField> fields;
	@SuppressWarnings("all")
	protected AndroidField getField(int fieldNumber) {
		fieldNumber--;
		if ((fieldNumber >= 0) && (fieldNumber < this.fields.size()))
			return this.fields.get(fieldNumber);
		return null;
	}

	public static RelativeLayout getCell(int x, int y) {
		return GUIBoard.bgLayouts[x][y];
	}

	private TextView[] playerLabels = new TextView[MAX_PLAYER_COUNT];
	private ImageView[] iconLabels = new ImageView[MAX_PLAYER_COUNT];
	private ImageView die1View, die2View;
	private Bitmap[] diceIcons = new Bitmap[6];
	private RelativeLayout inputLayout;
	private TextView tv;

	public static final int FIELDWIDTH = 65;
	public static final int FIELDHEIGHT = 65;

	private GUIBoard() {
		MainActivity.context.runOnUiThread(new Runnable() {
			@SuppressWarnings("synthetic-access")
			@Override public void run() {
				makeBase();
				makeBackGroundPanels();
				makeDice();
				makePlayerAreas();
				makeCenter();
				makeFields();
				makeCarPanes();
				makeInputPanel();

				makeAutogeneratedCrap();
			}
		});
		
	}

	private void makeFields() {
		this.fields = new GUIFieldFactory().makeDefaultFields();
	}

	/**
	 * Retrieves the singleton instance
	 * 
	 * @return the Board instance
	 */
	public static GUIBoard getInstance() {
		if(instance == null) instance = new GUIBoard();
		return instance;
	}

	public static void destroy() {
		// Board.getInstance().dispose();
		instance = null;
	}

	/**
	 * Makes images of the dice
	 */
	private void makeDice() {
		this.die1View = new ImageView(MainActivity.context);
		this.die1View.setId(generateViewId());
		this.die2View = new ImageView(MainActivity.context);
		this.die2View.setId(generateViewId());
		GridLayout.LayoutParams params1 = new GridLayout.LayoutParams(
				GridLayout.spec(4, 1), GridLayout.spec(3, 1));
		this.base.addView(this.die1View, params1);
		GridLayout.LayoutParams params2 = new GridLayout.LayoutParams(
				GridLayout.spec(7, 1), GridLayout.spec(6, 1));
		this.base.addView(this.die2View, params2);
		Bitmap image = BitmapFactory.decodeResource(this.die1View.getContext()
				.getResources(), R.drawable.dice);
		int height = (image.getHeight() + 1) / 6;
		for (int value = 0; value < 6; value++) {
			int x = 0;
			int y = height * value;
			this.diceIcons[value] = Bitmap.createBitmap(image, x, y,
					image.getWidth(), height - 1);
		}
	}

	/**
	 * Makes room for input fields
	 */
	private void makeInputPanel() {
		int x = 1, y = 1;
		int w = 9, h = 3;
		GridLayout.LayoutParams params = new GridLayout.LayoutParams(
				GridLayout.spec(y, h), GridLayout.spec(x, w));
		this.inputLayout = new RelativeLayout(MainActivity.context);
		this.base.addView(this.inputLayout, params);
		this.tv = new TextView(MainActivity.context);
		this.tv.setId(generateViewId());
		this.tv.setPadding(15, 15, 15, 15);
		RelativeLayout.LayoutParams tv_params = new RelativeLayout.LayoutParams(9*FIELDWIDTH, 3*FIELDHEIGHT);
		this.inputLayout.addView(this.tv, tv_params);
	}

	 /**
	 * Makes the components on which cars can be placed
	 */
	private void makeCarPanes() {
		for(AndroidField f : this.fields) {
			int x = f.getX();
			int y = f.getY();

			RelativeLayout carsLayout = new RelativeLayout(MainActivity.context);
			this.carPanes[x][y] = carsLayout;


			ImageView[] cars = new ImageView[MAX_PLAYER_COUNT];
			for(int i = 0; i < MAX_PLAYER_COUNT; i++) {
				ImageView car = new ImageView(MainActivity.context);
				cars[i] = car;
				car.setVisibility(View.VISIBLE);
				int top = (6*i) + 1;
				int left = (3*i) + 3;
				RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
				params.setMargins(left, top, 0, 0);
				carsLayout.addView(car, params);
			}

			f.setCarIcons(cars);
			f.getPanel().addView(carsLayout);

		}
	}
	/**
	 * Makes the center
	 */
	private void makeCenter() {
		RelativeLayout centerPanel = GUICenter.getInstance().getCenterPanel();
		GridLayout.LayoutParams params = new GridLayout.LayoutParams(
				GridLayout.spec(4, 3), GridLayout.spec(4, 3));
		this.base.addView(centerPanel, params);
		GUICenter.getInstance().displayDefault();
	}

	/**
	 * Makes the base
	 */
	private void makeBase() {
		this.base = new GridLayout(MainActivity.context);
		this.base.setId(generateViewId());
		this.base.setColumnCount(11);
		this.base.setRowCount(11);
		this.base.setBackgroundColor(MainActivity.context.getResources()
				.getColor(R.color.testcolor2));
	}

	/**
	 * Makes the background
	 */
	private void makeBackGroundPanels() {
		for (int x = 0; x < 11; x++) {
			for (int y = 0; y < 11; y++) {
				makeBackGroundPanel(x, y);
			}
		}
	}

	private RelativeLayout makeBackGroundPanel(int x, int y) {
		RelativeLayout cell = new RelativeLayout(MainActivity.context);
		cell.setId(generateViewId());
		cell.setBackgroundColor(MainActivity.context.getResources()
				.getColor(R.color.basecolor));
		GUIBoard.bgLayouts[x][y] = cell;
		// Add an empty textView to maintain size of empty cells
		TextView tv1 = new TextView(MainActivity.context);
		tv1.setId(generateViewId());
		tv1.setTag("cellsize");
		tv1.setHeight(FIELDWIDTH);
		tv1.setWidth(FIELDHEIGHT);
		tv1.setGravity(Gravity.CENTER);
		cell.addView(tv1);
		GridLayout.LayoutParams params = new GridLayout.LayoutParams(
				GridLayout.spec(y, 1), GridLayout.spec(x, 1));
		this.base.addView(cell, params);

		cell.setOnClickListener(new OnClickListener() {
			@SuppressWarnings("unused")
			@Override public void onClick(View v) {
				MainActivity.context.runOnUiThread(new Runnable() {
					@Override public void run() {
						GUICenter.getInstance().displayDefault();
					}
				});
			}
		});


		return cell;
	}

	/**
	 * Makes the components on which to show players
	 */
	private void makePlayerAreas() {
		int x = 7;
		for (int i = 0; i < MAX_PLAYER_COUNT; i++) {
			int y = 9 - i;

			ImageView iconLabel = new ImageView(MainActivity.context);
			iconLabel.setId(generateViewId());
			GridLayout.LayoutParams params1 = new GridLayout.LayoutParams(
					GridLayout.spec(y, 1), GridLayout.spec(x, 1));
			params1.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
			this.base.addView(iconLabel, params1);
			this.iconLabels[i] = iconLabel;

			TextView playerLabel = new TextView(MainActivity.context);
			playerLabel.setId(generateViewId());
			playerLabel.setHeight(1 * FIELDWIDTH);
			playerLabel.setWidth(2 * FIELDWIDTH);
			playerLabel.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
			GridLayout.LayoutParams params2 = new GridLayout.LayoutParams(
					GridLayout.spec(y, 1), GridLayout.spec(x + 1, 2));
			this.base.addView(playerLabel, params2);
			this.playerLabels[i] = playerLabel;
		}
	}
	/**
	 * Places dice on the board
	 * 
	 * @param x1
	 *            x-coordinate for die 1
	 * @param y1
	 *            y-coordinate for die 1
	 * @param faceValue1
	 *            value of die 1
	 * @param rotation1
	 *            the angle [0:359] of die 1
	 * @param x2
	 *            x-coordinate for die 2
	 * @param y2
	 *            y-coordinate for die 2
	 * @param faceValue2
	 *            value of die 2
	 * @param rotation2
	 *            the angle [0:359] of die 2
	 */
	public void setDice(int x1, int y1, int faceValue1, int rotation1, int x2,
			int y2, int faceValue2, int rotation2) {

		((GridLayout) this.die1View.getParent()).removeView(this.die1View);
		GridLayout.LayoutParams params1 = new GridLayout.LayoutParams(
				GridLayout.spec(x1, 1), GridLayout.spec(y1, 1));
		this.base.addView(this.die1View, params1);
		((GridLayout) this.die1View.getParent()).removeView(this.die2View);
		GridLayout.LayoutParams params2 = new GridLayout.LayoutParams(
				GridLayout.spec(x2, 1), GridLayout.spec(y2, 1));
		this.base.addView(this.die2View, params2);

		String[] dfvd = MainActivity.context.getResources().getStringArray(
				R.array.dice_face_values_description);
		this.die1View.setImageBitmap(this.getDiceIcon(faceValue1 - 1));
		this.die1View.setContentDescription(dfvd[faceValue1 - 1]);
		this.die1View.setRotation(rotation1);
		this.die2View.setImageBitmap(this.getDiceIcon(faceValue2 - 1));
		this.die2View.setContentDescription(dfvd[faceValue2 - 1]);
		this.die2View.setRotation(rotation2);
	}

	/**
	 * Add a player to the board
	 * 
	 * @param name
	 *            The name of the player
	 * @param balance
	 *            The initial balance
	 * @param playerColor
	 *            : Color
	 */
	public void addPlayer(String name, int balance, GUIColor playerColor) {
		Car<Bitmap> car = new AndroidGUICar.Builder().primaryColor(playerColor).build();
		if (playerColor != null) {
			addPlayer(name, balance, car);
		}
	}

	/**
	 * Add a player to the board
	 * 
	 * @param name
	 *            The name of the player
	 * @param balance
	 *            The initial balance
	 * @param car
	 *            : Type Car
	 */
	public void addPlayer(String name, int balance, Car<Bitmap> car) {
		if (GUIBoard.playerList[MAX_PLAYER_COUNT - 1] != null) {
			return;
		}
		int i = 0;
		for (; i < MAX_PLAYER_COUNT; i++) {
			if (GUIBoard.playerList[i] != null) {
				// No duplicate player names
				if (GUIBoard.playerList[i].getName().equals(name)) {
					return;
				}
			} else {
				break;
			}
		}
		GUIBoard.playerList[i] = new GUIPlayer(i, name, balance, car);
		updatePlayers();
	}

	/**
	 * Add a player to the board
	 * 
	 * @param name
	 *            The name of the player
	 * @param balance
	 *            The initial balance<br>
	 *            Automatic playerColor
	 */
	public void addPlayer(String name, int balance) {
		AndroidGUICar car = new AndroidGUICar.Builder().build();
		addPlayer(name, balance, car);
	}

	/**
	 * Updates the board in order to correct player balances
	 */
	public void updatePlayers() {
		int position = 0;
		for (GUIPlayer p : GUIBoard.playerList) {
			if (p != null) {
				Bitmap icon = p.getImage();

				this.iconLabels[position].setImageBitmap(icon);
				this.playerLabels[position].setText(p.getName() + "\r\n"
						+ p.getBalance());
				position++;
			} else {
				break;
			}
		}
	}

	/**
	 * Retrieves a player
	 * 
	 * @param name
	 *            The name of the player
	 * @return a Player object
	 */
	public GUIPlayer getPlayer(String name) {
		for (GUIPlayer p : GUIBoard.playerList) {
			if (p != null && name.equalsIgnoreCase(p.getName())) {
				return p;
			}
		}
		return null;
	}

	// /**
	// * Counts how many players are in the game
	// * @return number of players
	// */
	// public int getPlayerCount() {
	// int count = 0;
	// for(Player p : Board.playerList) {
	// if(p != null) {
	// count++;
	// } else {
	// break;
	// }
	// }
	// return count;
	// }
	private Bitmap getDiceIcon(int iconIndex) {
		if ((iconIndex >= this.diceIcons.length) || (iconIndex < 0))
			return null;
		return this.diceIcons[iconIndex];
	}

	/**
	 * Generate a value suitable for use in {@link #setId(int)}. This value will
	 * not collide with ID values generated at build time by aapt for R.id.
	 * 
	 * @return a generated ID value
	 */
	@SuppressWarnings("javadoc")
	public static int generateViewId() {
		for (;;) {
			final int result = sNextGeneratedId.get();
			// aapt-generated IDs have the high byte nonzero; clamp to the range
			// under that.
			int newValue = result + 1;
			if (newValue > 0x00FFFFFF)
				newValue = 1; // Roll over to 1, not 0.
			if (sNextGeneratedId.compareAndSet(result, newValue)) {
				return result;
			}
		}
	}

	/**
	 * Autogenerated DON'T CHANGE!
	 */
	private void makeAutogeneratedCrap() {
		((Activity) MainActivity.context).setContentView(this.base);
	}

	//	public RelativeLayout getInputLayout(){
	public View[] getInputLayout(){
		return new View[] {this.inputLayout, this.tv};
	}

	public void createFields(ArrayList<AndroidField> list) {
		if (this.fields.isEmpty()) {
			this.fields = list;
		}
	}
}